﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace II1svn
{
    public partial class Form1 : Form
    {

        class Org
        {
            public List<bool> body;
            public int cost;

            public Org()
            {
                this.body = new List<bool>();
            }

            public Org(Org o)
            {
                this.body = new List<bool>(o.body);
                this.cost = o.cost;                
            }

            public override string ToString()
            {
                string str ="";

                foreach (var b in body)
                    str += b ? "1" : "0";

                return str;
            }
        }

        public int bit_num { get; set; }//Snum
        public int org_num { get; set; }//Z
        public int B { get; set; }
        public int Q{ get; set; }
        public int G{ get; set; }
        public int L{ get; set; }

        public double Pm{ get; set; }
        public double Pvm{ get; set; }
        public double Pv{ get; set; }

        List<Org> orgs;
        List<int> S;
        Random rand;

        int sft;
        
        public Form1()
        {
            InitializeComponent();
            rand = new Random();
            B = 10;
        
            Pm = 0.025;
            Pvm = 0.99;
            Pv = 0.95;
            bit_num = 10;
            org_num = 25;

            G = 100;
            Q = 5;

            sft = 0;

            AddTB("org_num");
            AddTB("bit_num");
            AddTB("G");
            AddTB("Q");
            AddTB("Pm");
            AddTB("Pvm");
            AddTB("Pv");
            AddTB("B");
        }

        void AddTB(string text)
        {
            int ysft = 25;
            TextBox tb = new TextBox();
            Label lb = new Label();

            panel1.Controls.Add(tb);
            panel1.Controls.Add(lb);

            Point pos = new Point(10,10);
            pos.Offset(10, sft);

            lb.Text = text;
            lb.Location = pos;

            pos.Offset(100, 0);
            tb.Location = pos;
            tb.Size = new System.Drawing.Size(100, ysft - 1);
            
            tb.DataBindings.Add("Text", this, text);


            
            sft += ysft;
        }

        int cost(Org o)
        {
            int sum = 0;
            for (int i = 0; i < bit_num; i++)
            {
                if(o.body[i])
                sum += S[i];
            }

            return Math.Abs(B - sum);
        }
        
        void DoAlgorithm()
        {
            richTextBox1.Text += "\n================";
            chart1.Series[0].Points.Clear();

            orgs = new List<Org>();
            for (int i = 0; i < org_num; i++)//генерация
            {
                Org o = new Org();
                for (int j = 0; j < bit_num; j++)
                    o.body.Add(rand.NextDouble() > .5);

                orgs.Add(o);
            }

                for (int i = 0; i < G; i++)
                {
                    

                    Generation();//поколение

                    int sum = 0;
                    foreach (var o in orgs)
                    {
                        o.cost = cost(o);
                        sum += o.cost;
                    }
                    chart1.Series[0].Points.AddXY(i, sum);
                    richTextBox1.Text += "\n" + sum.ToString();
                }

                listBox1.Items.Clear();
                    //foreach (var o in orgs)
                    //{
                    //    richTextBox1.Text += "\n" + o.ToString();
                    //}

                foreach (var o in orgs)
                {
                    if(o.cost == 0)
                    listBox1.Items.Add(o.ToString()+"/"+o.cost.ToString());
                }
            
        }

        void Generation()
        {
            List<Org> formed = new List<Org>();

            //Воспроизводство
            for (int i = 0; i < Q && orgs.Count>1; i++)
            {
                
                Org a = orgs[rand.Next(orgs.Count)];
                orgs.Remove(a);
                Org b = orgs[rand.Next(orgs.Count)];
                orgs.Remove(b);

                formed.Add(a);
                formed.Add(b);

                Org c1 = new Org();
                Org c2 = new Org();
                L = rand.Next(bit_num);

                for (int j = 0; j < bit_num; j++)
                {
                    if (j < L)
                    {
                        c1.body.Add(a.body[j]);
                        c2.body.Add(b.body[j]);
                    }
                    else
                    {
                        c1.body.Add(b.body[j]);
                        c2.body.Add(a.body[j]);
                    }
                }

                formed.Add(c1);
                formed.Add(c2);
            }

            orgs.AddRange(formed);


            formed.Clear();
            //мутации
            foreach (var o in orgs)
            {
                Org m = new Org(o);
                for (int i = 0; i < bit_num; i++)
                {
                    if (rand.NextDouble() < Pm)
                        m.body[i] = !m.body[i];
                }

                if (cost(m) < cost(o))
                {
                    formed.Add(m);
                }
                else
                {
                    formed.Add(o);
                }
            }

            orgs = new List<Org>(formed);
            

            //Отбор
            
            formed.Clear();
            for (int i = 0; i < 2*Q && orgs.Count>1; i++)
            {
                Org a = orgs[rand.Next(orgs.Count)];
                orgs.Remove(a);
                Org b = orgs[rand.Next(orgs.Count)];
                orgs.Remove(b);

                if (cost(a) < cost(b) && rand.NextDouble()<Pv)
                {
                    formed.Add(a);
                }
                else
                {
                    formed.Add(b);
                }
            }

            orgs.AddRange(formed);
        }





        private void chart1_Click(object sender, EventArgs e)
        {

        }

        private void button1_Click(object sender, EventArgs e)
        {
            DoAlgorithm();
        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }

        private void button2_Click(object sender, EventArgs e)
        {
            
            richTextBox1.Text = "";
            S = new List<int>(); 
            
            for (int i = 0; i < bit_num; i++)
            {
                S.Add(rand.Next(10));
            }
            
            


 

            B = rand.Next(9 * bit_num);

            richTextBox1.Text += "\nS:";
            foreach (var s in S)
                richTextBox1.Text += s.ToString() + " ";

            richTextBox1.Text += "\nB=" + B.ToString();

            button1.Enabled = true;
        }


    }
}
